// Copyright (C) 1953-2022 NUDT
// Verilog module name - traffic_police
// Version: DGE_V3.4
// Created:
//         by - fenglin 
//         at - 9.2022
////////////////////////////////////////////////////////////////////////////
// Description:
//         descriptor generate
///////////////////////////////////////////////////////////////////////////

`timescale 1ns/1ps
 
module traffic_police
(
        i_clk           ,
        i_rst_n         ,
       
        iv_data         ,
        i_data_wr       ,
        iv_ipv          ,       
        iv_inject_dbufid,
        
        iv_free_bufid_num,
        iv_hpriority_be_threshold_value,
        iv_rc_threshold_value,
        iv_lpriority_be_threshold_value,
        ov_pkt_discard_cnt,
        
        ov_data          ,
        o_data_wr        ,
        ov_ipv           ,       
        ov_inject_dbufid ,
        o_desp_wr        
    );
// I/O
// clk & rst
input                   i_clk;
input                   i_rst_n;
//input
(*MARK_DEBUG="true"*)input      [8:0]       iv_data         ;
(*MARK_DEBUG="true"*)input                  i_data_wr       ;
(*MARK_DEBUG="true"*)input      [2:0]       iv_ipv          ;       
(*MARK_DEBUG="true"*)input      [4:0]       iv_inject_dbufid;

(*MARK_DEBUG="true"*)input       [8:0]       iv_free_bufid_num;
(*MARK_DEBUG="true"*)input       [8:0]       iv_hpriority_be_threshold_value;
(*MARK_DEBUG="true"*)input       [8:0]       iv_rc_threshold_value;
(*MARK_DEBUG="true"*)input       [8:0]       iv_lpriority_be_threshold_value;

output  reg [31:0]      ov_pkt_discard_cnt;
//output
output reg  [8:0]       ov_data           ;
output reg              o_data_wr         ;
output reg  [2:0]       ov_ipv            ;
output reg  [4:0]       ov_inject_dbufid  ;
output reg              o_desp_wr         ;

(*MARK_DEBUG="true"*)reg [3:0]   tp_state;
(*MARK_DEBUG="true"*)reg [5:0]   byte_cnt; 
localparam  IDLE_S              = 4'd1,
            TRAN_PKT_S          = 4'd2,
            DISC_S              = 4'd3;
always@(posedge i_clk or negedge i_rst_n)
    if(!i_rst_n) begin
        ov_data             <= 9'b0;
        o_data_wr           <= 1'b0;
        ov_ipv              <= 3'b0;
        ov_inject_dbufid    <= 5'b0;
        o_desp_wr           <= 1'b0;
        ov_pkt_discard_cnt  <= 32'b0;
        byte_cnt            <= 6'b0;        
        tp_state        <= IDLE_S;
    end
    else begin
        case(tp_state)
            IDLE_S:begin
                if((i_data_wr == 1'b1) && (iv_data[8] == 1'b1))begin//head
                    ov_data             <= iv_data;
                    ov_ipv              <= iv_ipv;
                    ov_inject_dbufid    <= iv_inject_dbufid;
                    if(iv_ipv <= 3'd1)begin 
                        if((iv_free_bufid_num <= iv_rc_threshold_value) || (iv_free_bufid_num <= iv_hpriority_be_threshold_value) || (iv_free_bufid_num <= iv_lpriority_be_threshold_value) || (iv_free_bufid_num == 9'h0))begin
                        //discard pkt when bufid under threshold or bufid is used up
                            o_data_wr            <= 1'h0;
                            ov_pkt_discard_cnt   <= ov_pkt_discard_cnt + 1'b1;
                            o_desp_wr            <= 1'b0;  
                            tp_state             <= DISC_S;
                        end 
                        else begin
                            o_data_wr           <= 1'h1;
                            byte_cnt            <= 6'b1;
                            o_desp_wr           <= 1'b1; 
                            tp_state            <= TRAN_PKT_S;
                        end
                    end
                    else if(iv_ipv == 3'd2)begin//tsmp
                        if((iv_free_bufid_num <= iv_rc_threshold_value) || (iv_free_bufid_num <= iv_hpriority_be_threshold_value)|| (iv_free_bufid_num == 9'h0))begin
                        //discard pkt when bufid under threshold or bufid is used up
                            o_data_wr                       <= 1'h0;
                            ov_pkt_discard_cnt              <= ov_pkt_discard_cnt + 1'b1;
                            o_desp_wr                       <= 1'b0; 
                            tp_state                        <= DISC_S;
                        end 
                        else begin
                            o_data_wr                <= 1'h1;
                            byte_cnt                 <= 6'b1;
                            o_desp_wr                <= 1'b1; 
                            tp_state <= TRAN_PKT_S;
                        end
                    end
                    else if(iv_ipv <= 3'd4)begin
                        if((iv_free_bufid_num <= iv_rc_threshold_value) || (iv_free_bufid_num == 9'h0))begin
                        //discard pkt when bufid under threshold or bufid is used up
                            o_data_wr                   <= 1'h0;
                            ov_pkt_discard_cnt          <= ov_pkt_discard_cnt + 1'b1;
                            o_desp_wr            <= 1'b0; 
                            tp_state    <= DISC_S;
                        end
                        else begin
                            o_data_wr            <= 1'h1;
                            o_desp_wr            <= 1'b1; 
                            tp_state             <= TRAN_PKT_S;
                        end
                    end
                    else if(iv_ipv <= 3'd7)begin
                        if(iv_free_bufid_num == 9'h0)begin
                        //discard pkt when bufid under threshold or bufid is used up
                            o_data_wr                   <= 1'h0;
                            ov_pkt_discard_cnt          <= ov_pkt_discard_cnt + 1'b1;
                            o_desp_wr            <= 1'b0; 
                            tp_state    <= DISC_S;
                        end
                        else begin
                            o_data_wr                   <= 1'h1;
                            o_desp_wr            <= 1'b1; 
                            tp_state    <= TRAN_PKT_S;
                        end
                    end
                    else begin
                        o_data_wr                   <= 1'h0;
                        o_desp_wr            <= 1'b0; 
                        tp_state    <= IDLE_S;                        
                    end
				end
				else begin
                    ov_data             <= 9'b0;
                    o_data_wr           <= 1'b0;
                    ov_ipv              <= 3'b0;
                    ov_inject_dbufid    <= 5'b0;
                    o_desp_wr           <= 1'b0;
                    ov_pkt_discard_cnt  <= 32'b0;
                    byte_cnt            <= 6'b0;        

					tp_state  <= IDLE_S;
				end
			end
            TRAN_PKT_S:begin           //standard ethernet type
                ov_data         <= iv_data;
                o_data_wr       <= i_data_wr;
                o_desp_wr            <= 1'b0; 
                //state judge
                if(i_data_wr == 1'b1 && iv_data[8] ==  1'b1)begin//tail
                    tp_state    <= IDLE_S;
                end
                else if(i_data_wr == 1'b1 && iv_data[8] ==  1'b0)begin//middle
                    tp_state    <= TRAN_PKT_S;
                end
                else begin//invalid
                    tp_state    <= IDLE_S;
                end
            end
            
            DISC_S:begin
                ov_data             <= 9'b0;
                o_data_wr           <= 1'b0;
                ov_ipv              <= 3'b0;
                ov_inject_dbufid    <= 5'b0;
                o_desp_wr           <= 1'b0;
                ov_pkt_discard_cnt  <= 32'b0;
                byte_cnt            <= 6'b0;   
                if(i_data_wr == 1'b1 && iv_data[8] == 1'b1)begin
                    tp_state        <= IDLE_S;
                end
                else begin
                    tp_state        <= DISC_S;
                end
            end

            default:begin
                ov_data             <= 9'b0;
                o_data_wr           <= 1'b0;
                ov_ipv              <= 3'b0;
                ov_inject_dbufid    <= 5'b0;
                o_desp_wr           <= 1'b0;
                ov_pkt_discard_cnt  <= 32'b0;
                byte_cnt            <= 6'b0;   
            end
        endcase
    end
endmodule